/*范本*/

/***
 * @methods:数组类型定义方式
 * */
let array1:string[] = ['0','56565']  // 统一定义数组中所有数据格式(基础类型)
let array3:Array<string> = ['0','56565']  // 用的比较多
let array4:[number,string,boolean]= [0,'5',true]   // 数组中每个值都有格式的定义称为元组
let array2:(string|number)[] = ['0',56565,4654]  // 统一定义数组中所有数据格式(联合类型)
let array5:string | number[] = [56565,4654]  // 统一定义值可以为数组,也可以为字符串(联合类型)
console.log(array1,array3,array4,array2,array5)
/***
 * @methods:类型别名
 * */
type dataType = string | number[] | {age:number,name:string }
let data:dataType = [ 5 ]//或者是'测试'


/***
 * @methods:函数类型定义方式
 * */
function fun(name:string='张三',age?:number):number {
  console.log(name,age)
  return 5
}
//表示返回的数据需要是number类型,
// 接受的数据name(需要字符串类型且必传,但如果形参上添加了默认值则则不传或者传undefined,null等也会使用默认值且不会报错)
//         age(的值非必传但传的格式需要是数字)
fun(undefined)
//-----------------------------------------------------------
function fun1(...gain:(number| string)[]):void {
  console.log(gain)
}
//表示gain将所有字段做数组格式的集合接收了接收
fun1(1,2,3,4,5,6,'集合')//void表示该函数必须没有返回值









/***
 * @methods:对象类型定义方式
 * */
let obj:{name:string,age:number, func():void//函数还有一种写法是  --- func:()=>void
} = {name:'张三', age:18, func(){}}
console.log(obj,'obj')

/***
 * @methods:接口类型定义方式(可以将它看做类型别名的样子,接口是只能为对象执行数据类型,类型别名可以针对所有数据)
 * */
interface objType{name:string,age?:number,func:()=>void}
let obj2:objType = {name:'测试数据',func(){}}

/***
 * @methods:接口继承
 * */
interface objType2 extends objType {ta: string | 0} //这里的意思是可以是字符串或者是数字0(重点记下,必须是)
let obj3:objType2 = {
  name:'测试数据',func(){},ta: 0
}

/***
 * @methods:类型推论(声明的时候直接定义值,ts会自己主动识别值的类型)
 * */
let num = 18

class pe {
  static a(){
    console.log('我哦if噢史家坡打飞机')
  }
}
// pe.a()
// new pe().a
type a = string
type b = number
type c = a & b
let ab:a = '00'

// 定义一个接口给对象使用
interface face<typea> {
  //定义函数a的形参值的类型为face接口的形参,并且函数执行完毕后的返回值为以接口face的形参格式为标砖的数组
  a : (val:typea)=>typea[]
}
let b:face<number> = {
  a(val){ return [val]}
}




//类型别名(定义一个多种类型的集合)
type typeAll = number | string
let b2:typeAll = 0
console.log(b2)

//定义两个接口给对象使用
/**
 * param: typ代表传进来的数据格式(接口泛型)
 * way:定义接口interface1和interface2,用来帮助对象obj规定他们可以拥有参数a和b,且格式为数字和字符
 * */
interface interface1<typ>{
  a:typ
}
interface interface2<abc>{
  b:abc
}
type typeName = interface1<number> & interface2<string>
let obj1:typeName = {
  a:0,
  b:'10'
}
console.log(obj1)



/**
 * param:
 * way:定义一个类型别名为baseType,可以接受4个参数,用来集合定义最后确定的所有可能性的数据类型
 * */
type baseType<typ,arrStr,obj,inter> = number | typ | arrStr | obj | inter
let arr:baseType<string,
  (string | boolean | number)[],
  (number|boolean),
  interface2<string>> = {
  b:'878'
}
console.log(arr)














// interface baseInterface<typeName>{
//   b:typeName
// }
// type baseTypea = baseInterface<baseType<string,(string | boolean | number)[],(number|boolean),interface2<string>>> | boolean
// let a:baseTypea = {
//   b:true
// }
// console.log(a)


/**
 * way:泛型
 * */

//基础的函数泛型
function f<type1>(val:type1):type1{return val}
f<string>('54')



// 使用extends keyof实现的泛型,下面的写法表示key1现在可以为对象type1中的任何一个键,keyof可以获取type1对象的所有键(可以理解为这个key1只能是type1里边的一个键)
function funs1<type1,key1 extends keyof type1>(obj:type1,key:key1){
  return obj[key]
}
let para1 = {name:"张三",age:15}
console.log(funs1(para1,'name'))



// keyof的展示实例
// type Dog = { name: string; age: number;  };
// type D = keyof Dog; //type D = "name" | "age"




/**
 * way:解读:类型objType1的第一个参数表示形参只能接受any类型(这里只有这三种:string | number | symbol),然后将传进来的类型用K去进行接受,最后使用[p in K]去遍历传进来的类型(可以传多个),用来决定键的格式只能为传进来的类型
 *          所以在调用的时候需要传前边三种格式中的任意一个才算符合规范,并且在实体对象ob中的键需要符合符合调用的时候穿进去的格式
 * */
type objType1<K extends keyof any, T>= {
  [p in K] : T
}

let ob:objType1<string,string> = {
  'dsgsdfg':'()=>{}'
}
